using System;

using Microsoft.Cci;
using Microsoft.FxCop.Sdk;
using Microsoft.FxCop.Sdk.Introspection;

namespace Tyng.Rules
{
	public abstract class IdentifierRuleBase<T> : RuleBase<T>
        where T : IdentifierRuleBase<T>
	{
		private bool _includeLocals;

		protected IdentifierRuleBase(bool includeLocals) { _includeLocals = includeLocals; }
		
		public override ProblemCollection Check(string namespaceName, TypeNodeList types)
		{
			string[] namespaces = namespaceName.Split('.');

			for (int i = 0; i < namespaces.Length; i++)
				CheckIdentifier(namespaces[i], null);

			return base.Problems;
		}

		private void CheckMember(Member member)
		{
			if (RuleUtilities.IsOverride(member))
				return;

			Field field = member as Field;
			
			if(field != null && ! member.IsVisibleOutsideAssembly)
				return;
		
			if(field != null && (! field.IsStatic || (! field.IsInitOnly && ! field.IsLiteral)))
				return;


			if(! member.IsSpecialName && member.Name.Name != "__dtor" && member.Name.Name != "{dtor}")
			{
				CheckIdentifier(member.Name.Name, member);
			}
		}

		private void CheckParameters(ParameterList parameters)
		{
			if (parameters != null)
			{
				for (int i = 0; i < parameters.Length; i++)
				{
					Parameter parameter = parameters[i];

					string name = parameter.Name.Name;

					if (name != null)
					{
						CheckIdentifier(name, parameters[i]);
					}
				}
			}
		}

		private void CheckLocals(Method method)
		{
			if(method == null)
				return;

			if(method.Instructions.Length >= 1)
			{
				LocalList locals = method.Instructions[0].Value as LocalList;

				if(locals != null && locals.Length > 0)
				{
					for(int i = 0; i < locals.Length; i++)
						CheckIdentifier(locals[i].Name.Name, locals[i]);
				}
			}
		}


		public override ProblemCollection Check(Member member)
		{
			CheckMember(member);

			ParameterList parameters = RuleUtilities.GetParameters(member);

			if((member.Name.Name != ".ctor" && member.Name.Name != "BeginInvoke" && member.Name.Name != "EndInvoke") || ! member.DeclaringType.IsAssignableTo(SystemTypes.MulticastDelegate) && (! member.IsSpecialName || ! member.Name.Name.StartsWith("set_")))
			{
				CheckParameters(parameters);
			}

			if(_includeLocals)
			{
				Method method = member as Method;

				CheckLocals(method);
			}

			return base.Problems;
		}

		public override ProblemCollection Check(TypeNode type)
		{
			if ((type.Flags & TypeFlags.Import) == TypeFlags.Import)
			{
				return null;
			}

			CheckIdentifier(type.Name.Name, type);

			return base.Problems;

		}

		private void CheckIdentifier(string identifier, Node target)
		{
			if(! IsValidIdentifier(identifier))
				Problems.Add(new Problem(GetResolution(identifier), target));
		}

		protected abstract bool IsValidIdentifier(string identifier);
	}
}
